package org.xinhe.example.quartz.management.manager;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.quartz.*;
import org.quartz.impl.matchers.GroupMatcher;
import org.quartz.utils.Key;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * <p>Title: ScheduleManager</p>
 * <p>Date: 17/1/2 </p>
 * <p>Description: 定时任务调度管理</p>
 *
 * @author xinhe.sun
 */
@Component
public class ScheduleManager implements InitializingBean {

    public static final Logger LOGGER = LoggerFactory.getLogger(ScheduleManager.class);

    @Autowired
    private SchedulerFactoryBean schedulerFactoryBean;

    private Scheduler scheduler = null;

    @Override
    public void afterPropertiesSet() throws Exception {
        scheduler = schedulerFactoryBean.getScheduler();
    }

    //region 作业列表

    /**
     * 获取所有作业组的名称
     *
     * @return groupName列表
     */
    public List<String> getJobGroups() throws SchedulerException {
        List<String> jobGroupNames = scheduler.getJobGroupNames();
        LOGGER.info("获取所有作业组，size = {}", CollectionUtils.size(jobGroupNames));
        LOGGER.debug("获取所有作业组，list = {}", jobGroupNames);
        return jobGroupNames;
    }

    /**
     * 获取触发器总数
     *
     * @param groupName 分组名称【可空，为空表示取默认分组】
     * @return 指定分组的触发器总数
     * @throws SchedulerException
     */
    public int countTriggers(String groupName) throws SchedulerException {
        LOGGER.info("根据分组名称获取触发器总数，groupName = {}", groupName);
        //如果分组名称为空，使用默认分组
        String groupNameChecked = checkGroupName(groupName);

        int count = scheduler.getTriggerKeys(GroupMatcher.triggerGroupEquals(groupNameChecked)).size();
        LOGGER.info("根据分组名称获取触发器总数，groupNameChecked = {},count = {}", groupNameChecked, count);
        return count;
    }

    /**
     * 获取某一组的作业列表
     *
     * @param groupName 分组名
     * @return 作业列表
     * @throws SchedulerException
     */
    public List<JobWrapper> getJobsByGroup(String groupName) throws SchedulerException {
        List<JobWrapper> jobList = new ArrayList<>();

        LOGGER.info("根据分组名称获取作业列表，groupName = {}", groupName);
        //如果分组名称为空，使用默认分组
        String groupNameChecked = checkGroupName(groupName);

        //获取作业Key列表
        Set<JobKey> jobKeys = scheduler.getJobKeys(GroupMatcher.jobGroupEquals(groupNameChecked));
        LOGGER.info("获取作业列表，size = {}", CollectionUtils.size(jobKeys));
        LOGGER.debug("获取作业列表，list = {}", jobKeys);

        for (JobKey jobKey : jobKeys) {
            //每个Trigger作为一个作业
            List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
            LOGGER.info("获取作业触发器列表，job = {}，size = {}", jobKey.getName(), CollectionUtils.size(triggers));
            LOGGER.debug("获取作业触发器列表，list = {}", triggers);

            for (Trigger trigger : triggers) {
                JobWrapper job = new JobWrapper();

                //展开作业详情
                job.setJobName(jobKey.getName());
                job.setTriggerName(trigger.getKey().getName());
                job.setDesc("触发器:" + trigger.getKey());
                Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
                job.setStatus(triggerState.name());
                if (trigger instanceof CronTrigger) {
                    CronTrigger cronTrigger = (CronTrigger) trigger;
                    String cronExpression = cronTrigger.getCronExpression();
                    job.setCron(cronExpression);
                }
                LOGGER.debug("封装作业信息，job = {}", job);

                jobList.add(job);
            }
        }
        return jobList;
    }
    //endregion

    //region 暂停触发器

    /**
     * 暂停触发器
     *
     * @param triggerName 触发器名称
     * @param groupName   分组名称
     * @throws SchedulerException
     */
    public void pauseTrigger(String triggerName, String groupName) throws SchedulerException {
        LOGGER.info("暂停触发器：triggerName = {}，groupName = {}", triggerName, groupName);

        //如果分组名称为空，使用默认分组
        String groupNameChecked = checkGroupName(groupName);

        TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, groupNameChecked);
        scheduler.pauseTrigger(triggerKey);
        LOGGER.info("暂停触发器完成。");
    }

    /**
     * 暂停触发器
     *
     * @param triggerName 触发器名称
     * @throws SchedulerException
     */
    public void pauseTrigger(String triggerName) throws SchedulerException {
        LOGGER.info("暂停触发器：triggerName = {}", triggerName);
        pauseTrigger(triggerName, Key.DEFAULT_GROUP);
    }
    //endregion

    //region 恢复触发器

    /**
     * 恢复触发器
     *
     * @param triggerName 触发器名称
     * @param groupName   分组名称
     * @throws SchedulerException
     */
    public void resumeTrigger(String triggerName, String groupName) throws SchedulerException {
        LOGGER.info("恢复触发器：triggerName = {}，groupName = {}", triggerName, groupName);

        //如果分组名称为空，使用默认分组
        String groupNameChecked = checkGroupName(groupName);

        TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, groupNameChecked);
        scheduler.resumeTrigger(triggerKey);
        LOGGER.info("恢复触发器完成。");
    }

    /**
     * 恢复触发器
     *
     * @param triggerName 触发器名称
     * @throws SchedulerException
     */
    public void resumeTrigger(String triggerName) throws SchedulerException {
        LOGGER.info("恢复作业：triggerName = {}", triggerName);
        resumeTrigger(triggerName, Key.DEFAULT_GROUP);
    }
    //endregion

    //region 删除触发器

    //region 暂停作业

    /**
     * 暂停作业
     *
     * @param jobName   作业名称
     * @param groupName 分组名称
     * @throws SchedulerException
     */
    public void pauseJob(String jobName, String groupName) throws SchedulerException {
        LOGGER.info("暂停作业：jobName = {}，groupName = {}", jobName, groupName);

        //如果分组名称为空，使用默认分组
        String groupNameChecked = checkGroupName(groupName);

        JobKey jobKey = JobKey.jobKey(jobName, groupNameChecked);
        scheduler.pauseJob(jobKey);
        LOGGER.info("暂停作业完成。");
    }

    /**
     * 暂停作业
     *
     * @param jobName 作业名称
     * @throws SchedulerException
     */
    public void pauseJob(String jobName) throws SchedulerException {
        LOGGER.info("暂停作业：jobName = {}", jobName);
        pauseJob(jobName, Key.DEFAULT_GROUP);
    }
    //endregion

    //region 恢复作业

    /**
     * 恢复作业
     *
     * @param jobName   作业名称
     * @param groupName 分组名称
     * @throws SchedulerException
     */
    public void resumeJob(String jobName, String groupName) throws SchedulerException {
        LOGGER.info("恢复作业：jobName = {}，groupName = {}", jobName, groupName);

        //如果分组名称为空，使用默认分组
        String groupNameChecked = checkGroupName(groupName);

        JobKey jobKey = JobKey.jobKey(jobName, groupNameChecked);
        scheduler.resumeJob(jobKey);
        LOGGER.info("恢复作业完成。");
    }

    /**
     * 恢复作业
     *
     * @param jobName 作业名称
     * @throws SchedulerException
     */
    public void resumeJob(String jobName) throws SchedulerException {
        LOGGER.info("恢复作业：jobName = {}", jobName);
        resumeJob(jobName, Key.DEFAULT_GROUP);
    }
    //endregion

    //region 删除作业

    /**
     * 删除作业
     *
     * @param jobName   作业名称
     * @param groupName 分组名称
     * @throws SchedulerException
     */
    public void deleteJob(String jobName, String groupName) throws SchedulerException {
        LOGGER.info("删除作业：jobName = {}，groupName = {}", jobName, groupName);

        //如果分组名称为空，使用默认分组
        String groupNameChecked = checkGroupName(groupName);

        JobKey jobKey = JobKey.jobKey(jobName, groupNameChecked);
        scheduler.deleteJob(jobKey);
        LOGGER.info("删除作业完成。");
    }

    /**
     * 删除作业
     *
     * @param jobName 作业名称
     * @throws SchedulerException
     */
    public void deleteJob(String jobName) throws SchedulerException {
        LOGGER.info("删除作业：jobName = {}", jobName);
        deleteJob(jobName, Key.DEFAULT_GROUP);
    }
    //endregion

    //region 立即执行作业

    /**
     * 执行作业
     * =======================
     * 立即执行一次
     *
     * @param jobName   作业名称
     * @param groupName 分组名称
     * @throws SchedulerException
     */
    public void triggerJob(String jobName, String groupName) throws SchedulerException {
        LOGGER.info("执行作业：jobName = {}，groupName = {}", jobName, groupName);

        //如果分组名称为空，使用默认分组
        String groupNameChecked = checkGroupName(groupName);

        JobKey jobKey = JobKey.jobKey(jobName, groupNameChecked);
        scheduler.triggerJob(jobKey);
        LOGGER.info("执行作业完成。");
    }

    /**
     * 执行作业
     *
     * @param jobName 作业名称
     * @throws SchedulerException
     */
    public void triggerJob(String jobName) throws SchedulerException {
        LOGGER.info("删除作业：jobName = {}", jobName);
        triggerJob(jobName, Key.DEFAULT_GROUP);
    }
    //endregion


    /**
     * 校验分组名称，如果为空返回默认分组
     *
     * @param groupName 待校验的分组名称
     * @return groupNameChecked
     */
    private String checkGroupName(String groupName) {
        return StringUtils.isBlank(groupName) ? Key.DEFAULT_GROUP : groupName;
    }

}
